// Have include guard.
#ifndef STATE_H
#define STATE_H

// Include files.
#include <map>
#include "WPILib.h"
#include "StateDoneCode.hpp"
#include "Services/Service.hpp"

// TODO: Move from Service-based States to Operation-based States.

/**
 *  The State class is used by the StateMachineController.
 *  
 *  The State class is a special RobotController that acts as a state in the state machine in StateMachineController.
 *  States stores a transition map that maps a StateDoneCode to another State.
 *  When the state is done, it sets the "done code".  When the done code is set, the state machine
 *  moves on to the State specified by the transition map.
 *  
 *  This class seems to work.
 */
class State :
	private Service
{
	friend class StateMachineService;
	
	public:
		State();
		virtual ~State();
		const std::map<StateDoneCode, State*> &GetTransitions();
		void AddTransition(State &state);
		void AddTransition(StateDoneCode doneCode, State &state);
		void RemoveTransition(StateDoneCode doneCode);
		StateDoneCode GetDoneCode();
		State &GetNextState();
	protected:
		virtual void HandleActivate();
		virtual void HandleDeactivate();
		virtual void HandlePeriodic();
		virtual void HandleContinuous();
		void SetDoneCode(StateDoneCode doneCode);
		
		/**
		 *  Add required control lock on an object (such as a RobotSubsystem).
		 *  
		 *  The lock is only acquired when the subscriber/service/operation is running.
		 *  This prevents two unrelated subscribers from using the same object at the same time. 
		 *  For more information on using locking, see our Thread Safety Manuel that does not exist yet. :P
		 *  
		 *  @param obj The object to be locked.
		 *  
		 *  @returns The obj parameter.
		 */
		template<typename T>
		T &RequireControl(T &obj)
		{
			return Subscriber::RequireControl(obj);
		}
	private:
		std::map<StateDoneCode, State*> m_transitions;
		StateDoneCode m_doneCode;
		
		void ActivateInternal();
		
		DISALLOW_COPY_AND_ASSIGN(State);
};

#endif // #ifndef STATE_H 
